﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.Owin;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.OAuth;
using System.Security.Principal;
using CanDoo.Oil.Core.Models;
using CanDoo.Core.Dependency;
using CanDoo.Oil.Core.Contracts;
using CanDoo.Oil.Core.DTOs;
using Newtonsoft.Json.Linq;
using CanDoo.Core.Logging;
using CanDoo.Core.Security;
using CanDoo.Data;
using CanDoo.Core.Context;
using CanDoo.Extensions;

namespace CanDoo.Oil.WebHost.Identity
{
    public class ApplicationOAuthProvider : OAuthAuthorizationServerProvider
    {
        IServiceProvider _serviceProvider;
        IOilSalesSerialNumContract _OilSalesSerialNumContract;
        IOperateLoger OperateLoger;
        IPermissionManager PermissionManager;

        public ApplicationOAuthProvider(IServiceProvider serviceProvider)
        {
            _serviceProvider = serviceProvider;
            _OilSalesSerialNumContract = ActivatorUtilities.GetServiceOrCreateInstance<IOilSalesSerialNumContract>(serviceProvider);
            OperateLoger = ActivatorUtilities.GetServiceOrCreateInstance<IOperateLoger>(serviceProvider);
            PermissionManager = ActivatorUtilities.GetServiceOrCreateInstance<IPermissionManager>(serviceProvider);
        }

        public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
        {
            PermissionManager.PageCode = "oauth";
            PermissionManager.PageTitle = "用户申请access_token";
            OperateLoger.FunctionInfo = PermissionManager.GetViewFunctionInfo();

            var userManager = _serviceProvider.GetService(typeof(CanDoo.Admin.Core.Identity.UserManager)) as CanDoo.Admin.Core.Identity.UserManager;
            CanDoo.Admin.Core.Models.User user = await userManager.FindAsync(context.UserName, context.Password);
            if (user == null)
            {
                context.SetError("invalid_grant", "用户名或密码不正确。");
                return;
            }
            ClaimsIdentity oAuthIdentity = userManager.CreateIdentity(user, OAuthDefaults.AuthenticationType);
            oAuthIdentity.AddClaim(new Claim("Ip", context.Request.RemoteIpAddress));
            oAuthIdentity.AddClaim(new Claim("ClientId", context.ClientId));

            //ClaimsIdentity cookiesIdentity = userManager.CreateIdentity(user,DefaultAuthenticationTypes.ApplicationCookie);

            AuthenticationProperties properties = new AuthenticationProperties();// CreateProperties(user.UserName);
            AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);
            context.Validated(ticket);

            //OperatorInfo operatorInfo = new OperatorInfo();
            //operatorInfo.UserId = user.Id;
            //operatorInfo.UserName = user.UserName;
            //operatorInfo.ClientId = context.ClientId;
            //operatorInfo.Name = user.Name;
            //operatorInfo.UserType = OperatorUserType.ClientUser;
            //operatorInfo.Ip = context.Request.RemoteIpAddress;

            //OperateLoger.OperationResult = new OperationResult(OperationResultType.Success, $"申请access_token成功");
            //await OperateLoger.SaveLogAsync(operatorInfo);

            //context.Request.Context.Authentication.SignIn(cookiesIdentity);
        }

        public override async Task GrantClientCredentials(OAuthGrantClientCredentialsContext context)
        {
            var clientId = context.ClientId;
            OilSalesSerialNum entity = await _OilSalesSerialNumContract.GetByClientAsync(clientId);//获取售油机信息

            PermissionManager.PageCode = "oauth";
            PermissionManager.PageTitle = "售油机申请access_token";
            OperateLoger.FunctionInfo = PermissionManager.GetViewFunctionInfo();
            OperatorInfo operatorInfo = new OperatorInfo();
            operatorInfo.UserId = entity.Id;
            operatorInfo.UserName = "ClientId" + context.ClientId;
            operatorInfo.ClientId = context.ClientId;
            operatorInfo.Name = "售油机" + context.ClientId;
            /*
             操作员类型
             0：
             1：管理系统用户

             2：售油机终端
             3：会员卡
             4：管理员卡
             */
            operatorInfo.UserType = 2;
            operatorInfo.Ip = context.Request.RemoteIpAddress;

            var oAuthIdentity = new ClaimsIdentity(context.Options.AuthenticationType);

            oAuthIdentity.AddClaim(new Claim(ClaimTypes.NameIdentifier, entity.Id.ToString()));

            oAuthIdentity.AddClaim(new Claim(ClaimTypes.Name, "ClientId" + context.ClientId));
            oAuthIdentity.AddClaim(new Claim("ClientId", context.ClientId));
            oAuthIdentity.AddClaim(new Claim("Ip", context.Request.RemoteIpAddress));

            var ticket = new AuthenticationTicket(oAuthIdentity, new AuthenticationProperties());
            context.Validated(ticket);

            OperateLoger.OperationResult = new OperationResult(OperationResultType.Success, $"申请access_token成功");
            await OperateLoger.SaveLogAsync(operatorInfo);

            await base.GrantClientCredentials(context);
        }

        //public override async Task TokenEndpoint(OAuthTokenEndpointContext context)
        //{
        //    foreach (KeyValuePair<string, string> property in context.Properties.Dictionary)
        //    {
        //        context.AdditionalResponseParameters.Add(property.Key, property.Value);
        //    }

        //    await base.TokenEndpoint(context);
        //}

        public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
        {
            string clientId;//对应售油机序列号
            string clientSecret;//对应售油机密钥
            var or = OperationResult.NoChanged;
            if (context.TryGetBasicCredentials(out clientId, out clientSecret) ||
                context.TryGetFormCredentials(out clientId, out clientSecret))
            {
                try
                {
                    OilSalesSerialNum entity = await _OilSalesSerialNumContract.GetByClientAsync(clientId, clientSecret);
                    if (entity != null)
                    {
                        context.Validated();
                        return;
                    }
                    context.SetError("没找到售油机信息");
                    or = new OperationResult(OperationResultType.QueryNull, "没找到售油机信息");
                }
                catch (Exception ex)
                {
                    context.SetError(ex.Message);
                    or = new OperationResult(OperationResultType.Error, ex.Message,null,ex.FormatMessage());
                }
            }

            PermissionManager.PageCode = "oauth";
            PermissionManager.PageTitle = "售油机验证";
            OperateLoger.FunctionInfo = PermissionManager.GetViewFunctionInfo();
            OperatorInfo operatorInfo = new OperatorInfo();
            operatorInfo.UserName = "ClientId" + clientId;
            operatorInfo.ClientId = clientId;
            operatorInfo.UserType = 2;
            operatorInfo.Name = "售油机" + clientId;
            operatorInfo.Ip = context.Request.RemoteIpAddress;
            OperateLoger.OperationResult = or;
            await OperateLoger.SaveLogAsync(operatorInfo);

            await base.ValidateClientAuthentication(context);
        }

        public override async Task ValidateClientRedirectUri(OAuthValidateClientRedirectUriContext context)
        {
            //if (context.ClientId == _publicClientId)
            //{
            //    Uri expectedRootUri = new Uri(context.Request.Uri, "/");

            //    if (expectedRootUri.AbsoluteUri == context.RedirectUri)
            //    {
            //        context.Validated();
            //    }
            //}
            context.Validated();
            await base.ValidateClientRedirectUri(context);
        }

        //public static AuthenticationProperties CreateProperties(string userName)
        //{
        //    IDictionary<string, string> data = new Dictionary<string, string>
        //    {
        //        { "userName", userName }
        //    };
        //    return new AuthenticationProperties(data);
        //}

        public override async Task GrantRefreshToken(OAuthGrantRefreshTokenContext context)
        {
            //var originalClient = context.Ticket.Properties.Dictionary["as:client_id"];
            //var currentClient = context.ClientId;

            //if (originalClient != currentClient)
            //{
            //    context.Rejected();
            //    return;
            //}

            //context.ClientId

            //var newId = new ClaimsIdentity(context.Ticket.Identity);
            //newId.AddClaim(new Claim("newClaim", "refreshToken"));

            //var newTicket = new AuthenticationTicket(newId, context.Ticket.Properties);
            //context.Validated(newTicket);

            await base.GrantRefreshToken(context);
        }
    }
}